package net.esj.basic.service.impl;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import java.util.List;

import javassist.util.proxy.MethodFilter;
import javassist.util.proxy.MethodHandler;

import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.validation.ConstraintViolationException;

import net.esj.basic.core.engine.support.translator.TranslateException;
import net.esj.basic.core.engine.support.validator.exception.MelonValidateException;
import net.esj.basic.dao.Dao;
import net.esj.basic.dao.DaoProxy;
import net.esj.basic.exception.MelonRuntimeException;
import net.esj.basic.pojo.PrimaryKey;
import net.esj.basic.pojo.UpdateType;
import net.esj.basic.pojo.proxy.DefaultPojoMethodFilter;
import net.esj.basic.pojo.proxy.DefaultPojoMethodHandler;
import net.esj.basic.pojo.proxy.PojoProxy;
import net.esj.basic.pojo.proxy.PojoProxyFactory;
import net.esj.basic.service.Service;
import net.esj.basic.utils.Validators;

import org.apache.log4j.Logger;
import org.springframework.transaction.annotation.Transactional;

@Transactional
public class ServiceImpl extends QueryBuilderServiceImpl implements Service {

	private Logger logger = Logger.getLogger(ServiceImpl.class);
	
	protected Dao dao;
	
	private MethodHandler methodHandler;
	
	private MethodFilter methodFilter;
	
	@Override
	public void delete(Object entity) {
		if(entity instanceof PojoProxy){
			getDao().delete(((PojoProxy)entity).self());
			return;
		}
		getDao().delete(entity);
	}

	@Override
	public void deleteAll(Collection c) {
		getDao().deleteAll(c);
	}

	@Override
	public <T> List<T> findAll(Class<T> clazz) {
		return getDao().findAll(clazz);
	}

	@Override
	public <T> List<T> findAll(Class<T> clazz, boolean cachable) {
		return getDao().findAll(clazz, cachable);
	}

	@Override
	public <T> T get(Serializable id, Class<T> clazz) {
		T t = getDao().get(id, clazz);
		try {
			t = PojoProxyFactory.getInstance().create(t, clazz, getMethodFilter(), getMethodHandler());
		} catch (InstantiationException e ){
			logger.error("pojo proxy create error", e);
		}catch(IllegalAccessException e) {
			logger.error("pojo proxy create error", e);
		} catch (InvocationTargetException e) {
			logger.error("pojo proxy create error", e);
		}
		return t;
	}
	
	@Override
	public <T, V> V get(Serializable id, Class<T> clazz, Class<V> targetClass) {
		return (V) autoTransVo(get(id, clazz), targetClass);
	}

	@Override
	public void save(Object entity) {
		try{
			if(entity instanceof PojoProxy){
				entity = ((PojoProxy)entity).self();
			}
			getDao().save(entity);
		}catch(ConstraintViolationException ex){
			packEsjValidateEx(ex);
		}
	}
	
	@Override
	public void save(Object voEntity, Class<?> clazz)
			throws MelonValidateException {
		Object entity = autoTransPo(voEntity, clazz);
		save(entity);
	}

	@Override
	public void save(Object entity,
			Class<?>... validateClazz) throws MelonValidateException {
		if(validateClazz!=null){
			validate(entity,validateClazz);
		}
		save(entity);
	}

	@Override
	public void saveOrUpdate(Object entity) {
		try{
			getDao().saveOrUpdate(entity);
		}catch(ConstraintViolationException cvex){
			packEsjValidateEx(cvex);
		}
	}
	
	@Override
	public void saveOrUpdate(Object entity, Class<?> clazz)
			throws MelonValidateException {
		entity = autoTransPo(entity, clazz);
		if(entity instanceof PrimaryKey){
			if(Validators.isEmpty(((PrimaryKey) entity).getId())){//防止空字符串导致变成UPDATE的操作
				((PrimaryKey) entity).setId(null);
			}
		}
		saveOrUpdate((PrimaryKey) entity);
	}

	@Override
	public void saveOrUpdate(Object entity, Class<?>... validateClazz)
			throws MelonValidateException {
		if(validateClazz!=null){
			validate(entity,validateClazz);
		}
		saveOrUpdate(entity);
	}

	
	@Override
	public void update(Object entity) {
		try{
			if(entity instanceof PojoProxy){
				entity = ((PojoProxy)entity).self();
			}
			getDao().update(entity);
		}catch(ConstraintViolationException cvex){
			packEsjValidateEx(cvex);
		}
	}
	
	@Override
	public void update(Object entity, Class<?> clazz)
			throws MelonValidateException {
		entity = autoTransPo(entity, clazz);
		update(entity);
	}

	@Override
	public void update(Object entity, 
			Class<?>... validateClazz) throws MelonValidateException {
		if(validateClazz!=null){
			validate(entity,validateClazz);
		}
		update(entity);
	}

	@Override
	public void update(Object entity, UpdateType type) {
		getDao().update(entity, type);
	}
	
	@Override
	public <T> Object translate(Object entity, Class<T> clazz) {
		try {
			return getTranslator().translate(entity, clazz);
		} catch (TranslateException e) {
			throw new MelonRuntimeException(e);
		}
	}

	@PostConstruct
	public void afterPropertiesSet() throws Exception {
		super.afterPropertiesSet();
		dao = DaoProxy.getProxy(Dao.class);
	}

	protected Dao getDao(){
		if(dao==null){
			dao = DaoProxy.getProxy(Dao.class);
		}
		return dao;
	}
	
	protected <T> T getDao(Class<T> daoClass){
		return DaoProxy.getProxy(daoClass);
	}
	
	public void setMethodHandler(MethodHandler methodHandler) {
		this.methodHandler = methodHandler;
	}

	public void setMethodFilter(MethodFilter methodFilter) {
		this.methodFilter = methodFilter;
	}

	private MethodHandler getMethodHandler() {
		if(methodHandler == null) {
			methodHandler = new DefaultPojoMethodHandler();
		}
		return methodHandler;
	}

	private MethodFilter getMethodFilter() {
		if(methodFilter == null){
			methodFilter = new DefaultPojoMethodFilter();
		}
		return methodFilter;
	}
	
}
